package com.zyf.concurrency.chapter14;

import com.zyf.concurrency.annotations.ThreadSafe;

/**
 * 当不满足前提条件时，有界缓存不会执行相应的操作
 * 尽管这种方法实现起来很简单，但使用起来却并非如此。异常应该用于发生异常条件的情
 * 况中[EJ Item 39]。“缓存已满”并不是有界缓存的一个异常条件，就像“红灯”并不表示交通
 * 信号灯出现了异常。在实现缓存时得到的简化(使调用者管理状态依赖性)并不能抵消在使用
 * 时存在的复杂性，因为现在调用者必须做好捕获异常的准备，并且在每次缓存操作时都需要
 * 重试日。程序清单14-4给出了对take的调用一并不是 很漂亮，尤其是当程序中有许多地方都
 * 调用put和take方法时。
 * create by yifeng
 */
@ThreadSafe
public class GrumpyBoundedBuffer <V> extends BaseBoundedBuffer<V> {
    protected GrumpyBoundedBuffer() {
        super(100);
    }

    public GrumpyBoundedBuffer(int size) {
        super(size);
    }

    public synchronized void put(V v) throws BufferFullException {
        if (isFull())
            throw new BufferFullException();
        doPut(v);
    }

    public synchronized V take() throws BufferEmptyException {
        if (isEmpty())
            throw new BufferEmptyException();
        return doTake();
    }

    class ExampleUsage {
        private GrumpyBoundedBuffer<String> buffer;
        int SLEEP_GRANULARITY = 50;

        void useBuffer() throws InterruptedException {
            try {
                // 程序清单14-4 调用GrumpyBoundedBuffer的代码
                /**
                 * 程序清单14-4中的客户代码不是实现重试的唯一方式。调用者可以不进入休眠状态，而直
                 * 接重新调用take方法，这种方法被称为忙等待或自旋等待。如果缓存的状态在很长一段时间内
                 * 都不会发生变化，那么使用这种方法就会消耗大量的CPU时间。但是，调用者也可以进入休
                 * 眠状态来避免消耗过多的CPU时间，但如果缓存的状态在刚调用完sleep就立即发生变化，那
                 * 么将不必要地休眠以段时间。因此，客户代码必须要在二者之间进行选择:要么容忍自旋导致
                 * 的CPU时钟周期浪费，要么容忍由于休眠而导致的低响应性。(除了忙等待与休眠之外，还有
                 * 一种选择就是调用Thread.yield,这相当于给调度器一个提示: 现在需要让出一定的时间使另一
                 * 个线程运行。假如正在等待另一个线程执行工作，那么如果选择让出处理器而不是消耗完整个
                 * CPU调度时间片，那么可以使整体的执行过程变快。)
                 */
                while (true) {
                    String item = buffer.take();
                    // use item
                    break;
                }
            } catch (BufferEmptyException e) {
                // 进入休眠
                Thread.sleep(SLEEP_GRANULARITY);
            }
        }
    }

}

class BufferFullException extends RuntimeException {
}

class BufferEmptyException extends RuntimeException {
}
